#include <Stage-4.1/stage.hh>

using namespace Stg;

class RatCamera : public Stg::Model
{
public:
	typedef struct
	{
		// GL_V3F
		GLfloat x, y, z;
	} ColoredVertex;

private:
	Stg::Canvas* _canvas;

	GLubyte* _frame_data;  //opengl read buffer
	GLubyte* _frame_color_data;  //opengl read buffer

	bool _valid_vertexbuf_cache;
	ColoredVertex* _vertexbuf_cache; //cached unit vectors with appropriate rotations (these must be scalled by z-buffer length)

	int _width;         //width of buffer
	int _height;        //height of buffer
	static const int _depth = 4;

	int _camera_quads_size;
	GLfloat* _camera_quads;
	GLubyte* _camera_colors;

	static Stg::Option showCameraData;

	Stg::PerspectiveCamera _camera;
	double _yaw_offset; //position camera is mounted at
	double _pitch_offset;

	///Take a screenshot from the camera's perspective. return: true for sucess, and data is available via FrameDepth() / FrameColor()

	GLint viewport[4];

public:
	RatCamera( World* world, Model* parent, unsigned width, unsigned height, const std::string& type);

	~RatCamera();

	virtual void Load();

	///Capture a new frame ( calls GetFrame )
	virtual void Update();

	///Draw Camera Model - TODO
	//virtual void Draw( uint32_t flags, Canvas* canvas );

	///Draw camera visualization
	virtual void DataVisualize(Stg::Camera* cam);

	///width of captured image
	int getWidth() const { return _width; }

	///height of captured image
	int getHeight() const { return _height; }

	///get reference to camera used
	const Stg::PerspectiveCamera& getCamera() const { return _camera; }

	bool GetFrame();

	///get a reference to camera depth buffer
	const GLfloat* FrameDepth() const { return (GLfloat*)_frame_data; }

	///get a reference to camera color image. 4 bytes (RGBA) per pixel
	const GLubyte* FrameColor() { ReadPixels(); return _frame_color_data; }

	///change the pitch
	void setPitch(double pitch) { _pitch_offset = pitch; _valid_vertexbuf_cache = false; }

	///change the yaw
	void setYaw(double yaw) { _yaw_offset = yaw; _valid_vertexbuf_cache = false; }

	void setFOV(float hori, float vert) { _camera.setFov(hori, vert); }

	void ReadPixels();
	void SetupCamera();


	// NEW FUNCTIONS
	void destroyBuffers();
	void setWidth(unsigned w) { _width = w; destroyBuffers(); }
	void setHeight(unsigned h) { _height = h; destroyBuffers(); }

  };
